import os
import sys

import rtconfig

if os.getenv('RTT_ROOT'):
    RTT_ROOT = os.getenv('RTT_ROOT')
else:
    RTT_ROOT = os.path.normpath(os.getcwd() + '/../../..')

sys.path = sys.path + [os.path.join(RTT_ROOT, 'tools')]


try:
    from building import *
except:
    print('Cannot found RT-Thread root directory, please check RTT_ROOT')
    print(RTT_ROOT)
    exit(-1)

if os.getenv('EMBARC_BSP_ROOT'):
    EMBARC_BSP_ROOT = os.getenv('EMBARC_BSP_ROOT')
else:
    EMBARC_BSP_ROOT = RTT_ROOT + '/bsp/synopsys/boards/packages/embARC_bsp-upstream'

if not os.path.isdir(EMBARC_BSP_ROOT):
    print('Cannot found embarc_bsp root directory, please check EMBARC_BSP_ROOT')
    print(EMBARC_BSP_ROOT)
    exit(-1)

SUPPORTED_BOARD_DIR = EMBARC_BSP_ROOT + '/board'
SUPPORTED_BOARD = [d for d in os.listdir(SUPPORTED_BOARD_DIR) if os.path.isdir(os.path.join(SUPPORTED_BOARD_DIR,d))]
print 'supported BOARD = ' + str(SUPPORTED_BOARD)

AddOption('--BOARD',
        dest = 'BOARD',
        type='string',
        nargs=1,
        action = 'store',
        default = 'emsk',
        help = 'select board')

AddOption('--BD_VER',
        dest = 'BD_VER',
        type='string',
        nargs=1,
        action = 'store',
        default = '23',
        help = 'select bd_ver')

AddOption('--CUR_CORE',
        dest = 'CUR_CORE',
        type='string',
        nargs=1,
        action = 'store',
        default = 'arcem9d',
        help = 'select cur_core')

AddOption('--TOOLCHAIN',
        dest = 'TOOLCHAIN',
        type='string',
        nargs=1,
        action = 'store',
        default = 'gnu',
        help = 'select toolchain')

AddOption('--OLEVEL',
        dest = 'OLEVEL',
        type='string',
        nargs=1,
        action = 'store',
        default = 'O2',
        help = 'select optimize level')

AddOption('--mdb',
        dest = 'mdb',
        action = 'store_true',
        default = False,
        help = 'use mdb to debug the elf')

AddOption('--gdb',
        dest = 'gdb',
        action = 'store_true',
        default = False,
        help = 'use gdb to debug the elf')

AddOption('--embarc_build',
        dest = 'embarc_build',
        action = 'store_true',
        default = False,
        help = 'to generate embarc_lib')

AddOption('--embarc_clean',
        dest = 'embarc_clean',
        action = 'store_true',
        default = False,
        help = 'to clean embarc_lib')

if GetOption('BOARD'):
    board = GetOption('BOARD')
    if board not in SUPPORTED_BOARD:
        print 'board %s not supported, available boards:' % board
        print SUPPORTED_BOARD
        exit(0)
    else:
        BOARD = board
        print 'get BOARD = [%s]' % board

if BOARD == 'emsdp':
    SUPPORTED_BD_VER = ['rev2']
else:
    SUPPORTED_BD_VER_DIR = SUPPORTED_BOARD_DIR + '/' + BOARD + '/configs'
    SUPPORTED_BD_VER = [d for d in os.listdir(SUPPORTED_BD_VER_DIR) if os.path.isdir(os.path.join(SUPPORTED_BD_VER_DIR,d))]
print 'supported BD_VER = ' + str(SUPPORTED_BD_VER)

if GetOption('BD_VER'):
    bd_ver = GetOption('BD_VER')
    if bd_ver not in SUPPORTED_BD_VER:
        print 'bd_ver %s not supported, available bd_ver:' % bd_ver
        print SUPPORTED_BD_VER
        exit(0)
    else:
        BD_VER = bd_ver
        print 'get BD_VER = [%s]' % BD_VER

if BOARD == 'emsdp':
    SUPPORTED_CORE_DIR = SUPPORTED_BOARD_DIR + '/' + BOARD + '/rev2/configs'
    SUPPORTED_CORE = [d for d in os.listdir(SUPPORTED_CORE_DIR) if os.path.isdir(os.path.join(SUPPORTED_CORE_DIR,d))]
else:
    SUPPORTED_CORE_DIR = SUPPORTED_BD_VER_DIR + '/' + BD_VER + '/tcf'
    SUPPORTED_CORE = [os.path.splitext(d)[0] for d in os.listdir(SUPPORTED_CORE_DIR)]

print 'supported CUR_CORE = ' + str(SUPPORTED_CORE)

if GetOption('CUR_CORE'):
    cur_core = GetOption('CUR_CORE')
    if cur_core not in SUPPORTED_CORE:
        print 'cur_core %s not supported, available cur_core:' % cur_core
        print SUPPORTED_CORE
        exit(0)
    else:
        CUR_CORE = cur_core
        print 'get CUR_CORE = [%s]' % CUR_CORE

SUPPORTED_TOOLCHAIN = ['mw', 'gnu']

print 'supported TOOLCHAIN = ' + str(SUPPORTED_TOOLCHAIN)

if GetOption('TOOLCHAIN'):
    toolchain = GetOption('TOOLCHAIN')
    if toolchain not in SUPPORTED_TOOLCHAIN:
        print 'toolchain %s not supported, available toolchain:' % toolchain
        print SUPPORTED_TOOLCHAIN
        exit(0)
    else:
        TOOLCHAIN = toolchain
        print 'get TOOLCHAIN = [%s]' % TOOLCHAIN

SUPPORTED_OLEVEL = ['O0', 'O2', 'Os']

print 'supported OLEVEL = ' + str(SUPPORTED_OLEVEL)

if GetOption('OLEVEL'):
    olevel = GetOption('OLEVEL')
    if olevel not in SUPPORTED_OLEVEL:
        print 'olevel %s not supported, available olevel:' % toolchain
        print SUPPORTED_OLEVEL
        exit(0)
    else:
        OLEVEL = olevel
        print 'get OLEVEL = [%s]' % olevel



EMBARC_LIB_PATH = EMBARC_BSP_ROOT + '/obj_%s_%s/%s_%s'%(BOARD, BD_VER, TOOLCHAIN, CUR_CORE)
# print 'EMBARC_LIB_PATH = %s'%EMBARC_LIB_PATH

TARGET = 'rtthread_snps_embarc.elf'
# print 'TARGET = %s'%TARGET

# ip_ph_dir = EMBARC_BSP_ROOT + '/device/peripheral'
# ip_ph_path = [os.path.join(ip_ph_dir,d) for d in os.listdir(ip_ph_dir) if os.path.isdir(os.path.join(ip_ph_dir,d))]

if BOARD == 'emsdp':
    board_inc_path = [SUPPORTED_CORE_DIR, SUPPORTED_CORE_DIR + '/%s/include'%CUR_CORE]
else:
    board_inc_path = [EMBARC_BSP_ROOT + '/board/%s/configs/%s'%(BOARD, BD_VER)]

# print 'board_inc_path = %s' % board_inc_path
# print 'ip_dw_path = %s' % ip_dw_path
# print 'ip_ss_path = %s' % ip_ss_path
# print 'ip_ph_path = %s' % ip_ph_path

EMBARC_CPPPATH = [  EMBARC_BSP_ROOT,
                    EMBARC_BSP_ROOT + '/include',
                    EMBARC_BSP_ROOT + '/board',
                    EMBARC_LIB_PATH + '/embARC_generated',
                 ] + board_inc_path
#print "EMBARC_CPPPATH: %s"%EMBARC_CPPPATH

if TOOLCHAIN == 'mw':
    EXEC_PATH 	= 'C:/ARC/MetaWare/arc/bin'
    MAKE = 'gmake'
    PREFIX = ''
    CC = 'ccac'
    CXX = 'ccac'
    AS = 'ccac'
    AR = 'arac'
    LINK = 'ccac'
    TARGET_EXT = 'elf'
    SIZE = 'sizeac'
    OBJDUMP = 'elfdumpac'
    OBJCPY = 'elf2bin'
    DBG = 'mdb'

    OPT_ARG_FILE = ' @' + EMBARC_LIB_PATH + '/embARC_generated/ccac.arg '
    MDB_ARG_FILE = ' @' + EMBARC_LIB_PATH + '/embARC_generated/mdb.arg '
    COMMON_COMPILE_OPT = ' -Hnoccm -Hnosdata -Wincompatible-pointer-types -Hnocopyr -Hpurge -fdata-sections -g -%s '%(OLEVEL)
    COMMON_DEFINES = ' -DBOARD_%s -D__MW__ -DEMBARC_TCF_GENERATED ' % BOARD.upper()

    CFLAGS = OPT_ARG_FILE + COMMON_COMPILE_OPT + COMMON_DEFINES + ' -Hnocplus '
    CXXFLAGS = OPT_ARG_FILE + COMMON_COMPILE_OPT + COMMON_DEFINES
    AFLAGS = ' -c' + OPT_ARG_FILE + COMMON_COMPILE_OPT + COMMON_DEFINES + ' -Hasmcpp -I%s -I%s/embARC_generated -I%s/include '%(EMBARC_BSP_ROOT, EMBARC_LIB_PATH, EMBARC_BSP_ROOT)

    LINKER_SCRIPT_FILE = RTT_ROOT + '/bsp/synopsys/boards/linker_template_mw.ld'
    LINK_SCRIPT = EMBARC_LIB_PATH + '/linker_mw.ldf'

    LFLAGS = ' -Hhostlink ' + OPT_ARG_FILE + ' -Hnocopyr -Hnosdata -Hnocrt -Hldopt=-Coutput=rtthread_snps_embarc.map -Hldopt=-Csections -Hldopt=-Ccrossfunc -Hldopt=-Csize -zstdout %s' % LINK_SCRIPT

elif TOOLCHAIN == 'gnu':
    EXEC_PATH 	= 'C:/arc_gnu/bin'
    MAKE = 'make'
    PREFIX = 'arc-elf32-'
    CC = PREFIX + 'gcc'
    CXX = PREFIX + 'g++'
    AS = PREFIX + 'gcc'
    AR = PREFIX + 'ar'
    LINK = PREFIX + 'gcc'
    TARGET_EXT = 'elf'
    SIZE = PREFIX + 'size'
    OBJDUMP = PREFIX + 'objdump'
    OBJCPY = PREFIX + 'objcopy'
    DBG = PREFIX + 'gdb'

    OPT_ARG_FILE = ' @' + EMBARC_LIB_PATH + '/embARC_generated/gcc.arg '
    MDB_ARG_FILE = ' @' + EMBARC_LIB_PATH + '/embARC_generated/mdb.arg '
    COMMON_COMPILE_OPT = ' -ffunction-sections -fdata-sections -mno-sdata -g -%s '%(OLEVEL)
    COMMON_DEFINES = ' -DBOARD_%s -D__GNU__ -DEMBARC_TCF_GENERATED ' % BOARD.upper()

    CFLAGS = OPT_ARG_FILE + COMMON_COMPILE_OPT + COMMON_DEFINES + ' -std=gnu99 '
    CXXFLAGS = OPT_ARG_FILE + COMMON_COMPILE_OPT + COMMON_DEFINES
    AFLAGS = ' -c ' + OPT_ARG_FILE + COMMON_COMPILE_OPT + COMMON_DEFINES + ' -x assembler-with-cpp -I%s -I%s/embARC_generated -I%s/include '%(EMBARC_BSP_ROOT, EMBARC_LIB_PATH, EMBARC_BSP_ROOT)

    LINKER_SCRIPT_FILE = RTT_ROOT + '/bsp/synopsys/boards/linker_template_gnu.ld'
    LINK_SCRIPT = EMBARC_LIB_PATH + '/linker_gnu.ldf'

    LFLAGS = ' --specs=nsim.specs ' + OPT_ARG_FILE + ' -mno-sdata -nostartfiles -Wl,--gc-sections,-Map=rtthread_snps_embarc.map,-cref,-u,system_vectors -T %s ' % LINK_SCRIPT

    OPENOCD_SCRIPT_ROOT = EXEC_PATH + '/../share/openocd/scripts'
    OPENOCD_CFG_FILE = OPENOCD_SCRIPT_ROOT + '/board/snps_em_sk_v2.2.cfg'

    OPENOCD_OPTIONS  = '-s %s -f %s' % (OPENOCD_SCRIPT_ROOT, OPENOCD_CFG_FILE)

    DBG_HW_FLAGS = ''' -ex "target remote | openocd --pipe %s" -ex "load" ''' % OPENOCD_OPTIONS

else :
    print 'TOOLCHAIN %s is not supported, available toolchain:' % TOOLCHAIN
    print SUPPORTED_TOOLCHAIN
    exit(-1)

env = Environment(ENV = os.environ, tools = ['mingw'],
        AS = AS, ASFLAGS = AFLAGS,
        CC = CC, CCFLAGS = CFLAGS,
        AR = AR, ARFLAGS = '-rc',
        LINK = LINK, LINKFLAGS = LFLAGS,
        LIBS = ['embarc'], LIBPATH = EMBARC_LIB_PATH,
        CPPPATH = EMBARC_CPPPATH
        )
env.PrependENVPath('PATH', EXEC_PATH)

Export('RTT_ROOT')
Export('rtconfig')

embarc_cd_cmd = ' cd %s '%EMBARC_BSP_ROOT
embarc_make_cmd = ' %s -f options/options.mk BOARD=%s BD_VER=%s CUR_CORE=%s TOOLCHAIN=%s V=1 OLEVEL=%s LINKER_SCRIPT_FILE=%s embarc_lib '%(MAKE,BOARD, BD_VER, CUR_CORE, TOOLCHAIN, OLEVEL, LINKER_SCRIPT_FILE)
embarc_clean_cmd = ' %s -f options/options.mk distclean '%MAKE

if GetOption('embarc_build'):
    print 'os.system: ' + embarc_cd_cmd + ' && ' + embarc_make_cmd
    os.system(embarc_cd_cmd + ' && ' + embarc_make_cmd)
    exit(0)

if GetOption('embarc_clean'):
    os.system(embarc_cd_cmd + ' && ' + embarc_clean_cmd)
    exit(0)

if GetOption('gdb'):
    if os.path.isfile(TARGET):
        os.system(DBG + DBG_HW_FLAGS + TARGET)
    else:
        print TARGET + 'not exist, please build first!!'
    exit(0)

if GetOption('mdb'):
    if os.path.isfile(TARGET):
        startup_path = EMBARC_BSP_ROOT + '/arc/startup'
        if BOARD == 'nsim':
            os.system('mdb -source_path=%s -nooptions -nogoifmain -toggle=include_local_symbols=1 -nsim -off=binary_stdin -off=binary_stdout \
            -on=load_at_paddr -on=reset_upon_restart -off=flush_pipe -off=cr_for_more -OKN %s '%(startup_path, MDB_ARG_FILE) + rtconfig.TARGET)
        else:
            os.system('mdb -source_path=%s -nooptions -nogoifmain -toggle=include_local_symbols=1 -hard -digilent '%startup_path + rtconfig.TARGET)
    else:
        print TARGET + 'not exist, please build first!!'
    exit(0)

# os.system(embarc_cd_cmd + ' && ' + embarc_make_cmd)

# prepare building environment
objs = PrepareBuilding(env, RTT_ROOT)

# if the linker script changed, relink the target
Depends(TARGET, LINK_SCRIPT)

# make a building
DoBuilding(TARGET, objs)
